#include "wx/wxprec.h"
#include "wx/filefn.h"
#include "wx/file.h"
#include "wx/filename.h"
#include "wx/dir.h"
#include "wx/tokenzr.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !wxONLY_WATCOM_EARLIER_THAN(1,4)
#if !(defined(_MSC_VER) && (_MSC_VER > 800))
#include <errno.h>
#endif
#endif

#if defined(__VMS__)
#include <fab.h>
#endif

#ifdef _MSC_VER
#define HAVE_WGETCWD
#endif

#ifndef _MAXPATHLEN
#define _MAXPATHLEN 1024
#endif

static wxChar wxFileFunctionsBuffer[4 * _MAXPATHLEN];

#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
const int wxInvalidOffset = -1;
#endif

#define OS_FILENAME(s) (s.fn_str())

#ifdef wxNEED_WX_UNISTD_H

int wxStat( const wxChar *file_name, wxStructStat *buf ) {
  return stat( wxConvFile.cWX2MB( file_name ), buf );
}

int wxLstat( const wxChar *file_name, wxStructStat *buf ) {
  return lstat( wxConvFile.cWX2MB( file_name ), buf );
}

int wxAccess( const wxChar *pathname, int mode ) {
  return access( wxConvFile.cWX2MB( pathname ), mode );
}

int wxOpen( const wxChar *pathname, int flags, mode_t mode ) {
  return open( wxConvFile.cWX2MB( pathname ), flags, mode );
}

#endif // wxNEED_WX_UNISTD_H

#if wxUSE_UNICODE && defined __BORLANDC__ \
&& __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551

int wxOpen( const wchar_t *pathname, int flags, mode_t mode ) {
  int moreflags = 0;
  if( ( flags & O_CREAT ) && !( flags & O_EXCL ) && ( mode & wxS_IWUSR ) != 0 ) {
    moreflags = O_EXCL;
  }
  int fd = _wopen( pathname, flags | moreflags, mode );
  // the file was actually created and needs fixing
  if( fd != -1 && ( flags & O_CREAT ) != 0 && ( mode & wxS_IWUSR ) != 0 ) {
    close( fd );
    _wchmod( pathname, mode );
    fd = _wopen( pathname, flags & ~( O_EXCL | O_CREAT ) );
  }
  // the open failed, but it may have been because the added O_EXCL stopped
  // the opening of an existing file, so try again without.
  else if( fd == -1 && moreflags != 0 ) {
    fd = _wopen( pathname, flags & ~O_CREAT );
  }
  return fd;
}

#endif

bool wxPathList::Add( const wxString& path ) {
  wxFileName fn( path + wxFileName::GetPathSeparator() );
  if( !fn.Normalize( wxPATH_NORM_TILDE | wxPATH_NORM_LONG | wxPATH_NORM_ENV_VARS ) ) {
    return false;
  }
  wxString toadd = fn.GetPath();
  if( Index( toadd ) == wxNOT_FOUND ) {
    wxArrayString::Add( toadd );
  }      // do not add duplicates
  return true;
}

void wxPathList::Add( const wxArrayString &arr ) {
  for( size_t j = 0; j < arr.GetCount(); j++ ) {
    Add( arr[j] );
  }
}

// Add paths e.g. from the PATH environment variable
void wxPathList::AddEnvList( const wxString& ( envVariable ) ) {
  // No environment variables on WinCE
  static const wxChar PATH_TOKS[] = wxT( ":;" );
  wxString val;
  if( wxGetEnv( envVariable, &val ) ) {
    // split into an array of string the value of the env var
    wxArrayString arr = wxStringTokenize( val, PATH_TOKS );
    WX_APPEND_ARRAY( *this, arr );
  }
}

bool wxPathList::EnsureFileAccessible( const wxString& path ) {
  return Add( wxPathOnly( path ) );
}

bool wxPathList::Member( const wxString& path ) const {
  return Index( path ) != wxNOT_FOUND;
}

wxString wxPathList::FindValidPath( const wxString& file ) const {
  wxFileName fn( file );
  wxString strend;
  if( !fn.Normalize( wxPATH_NORM_TILDE | wxPATH_NORM_LONG | wxPATH_NORM_ENV_VARS ) ) {
    return wxEmptyString;
  }
  wxASSERT_MSG( !fn.IsDir(), wxT( "Cannot search for directories; only for files" ) );
  if( fn.IsAbsolute() ) {
    strend = fn.GetFullName();
  }      // search for the file name and ignore the path part
  else
  { strend = fn.GetFullPath(); }
  for( size_t i = 0; i < GetCount(); i++ ) {
    wxString strstart = Item( i );
    if( !strstart.IsEmpty() && strstart.Last() != wxFileName::GetPathSeparator() ) {
      strstart += wxFileName::GetPathSeparator();
    }
    if( wxFileExists( strstart + strend ) ) {
      return strstart + strend;
    }        // Found!
  }
  return wxEmptyString;                    // Not found
}

wxString wxPathList::FindAbsoluteValidPath( const wxString& file ) const {
  wxString f = FindValidPath( file );
  if( f.empty() || wxIsAbsolutePath( f ) ) {
    return f;
  }
  wxString buf = ::wxGetCwd();
  if( !wxEndsWithPathSeparator( buf ) ) {
    buf += wxFILE_SEP_PATH;
  }
  buf += f;
  return buf;
}

static inline wxChar* MYcopystring( const wxString& s ) {
  wxChar* copy = new wxChar[s.length() + 1];
  return wxStrcpy( copy, s.c_str() );
}

static inline wxChar* MYcopystring( const wxChar* s ) {
  wxChar* copy = new wxChar[wxStrlen( s ) + 1];
  return wxStrcpy( copy, s );
}


bool wxFileExists( const wxString& filename ) {
  wxStructStat st;
  return wxStat( filename, &st ) == 0 && S_ISREG( st.st_mode );
}

bool wxIsAbsolutePath( const wxString& filename ) {
  if( !filename.empty() ) {
    if( filename[0] == wxT( '/' ) ) {
      return true;
    }
  }
  return false ;
}

void wxStripExtension( wxChar *buffer ) {
  int len = wxStrlen( buffer );
  int i = len - 1;
  while( i > 0 ) {
    if( buffer[i] == wxT( '.' ) ) {
      buffer[i] = 0;
      break;
    }
    i --;
  }
}

void wxStripExtension( wxString& buffer ) {
  for( size_t i = buffer.length() - 1; i != wxString::npos; --i ) {
    if( buffer.GetChar( i ) == wxT( '.' ) ) {
      buffer = buffer.Left( i );
      break;
    }
  }
}

wxChar *wxRealPath( wxChar *path ) {
  static const wxChar SEP = wxT( '/' );
  if( path[0] && path[1] ) {
    wxChar *p;
    if( path[2] == SEP && path[1] == wxT( '.' ) ) {
      p = &path[0];
    } else {
      p = &path[2];
    }
    for( ; *p; p++ ) {
      if( *p == SEP ) {
        if( p[1] == wxT( '.' ) && p[2] == wxT( '.' ) && ( p[3] == SEP || p[3] == wxT( '\0' ) ) ) {
          wxChar *q;
          if( q[0] == SEP && ( q[1] != wxT( '.' ) || q[2] != wxT( '.' ) || q[3] != SEP )
              && ( q - 1 <= path || q[-1] != SEP ) ) {
            wxStrcpy( q, p + 3 );
            if( path[0] == wxT( '\0' ) ) {
              path[0] = SEP;
              path[1] = wxT( '\0' );
            }
            p = q - 1;
          }
        } else if( p[1] == wxT( '.' ) && ( p[2] == SEP || p[2] == wxT( '\0' ) ) ) {
          wxStrcpy( p, p + 2 );
        }
      }
    }
  }
  return path;
}

wxString wxRealPath( const wxString& path ) {
  wxChar *buf1 = MYcopystring( path );
  wxChar *buf2 = wxRealPath( buf1 );
  wxString buf( buf2 );
  delete [] buf1;
  return buf;
}

wxChar *wxCopyAbsolutePath( const wxString& filename ) {
  if( filename.empty() ) {
    return ( wxChar * ) NULL;
  }
  if( ! wxIsAbsolutePath( wxExpandPath( wxFileFunctionsBuffer, filename ) ) ) {
    wxString buf = ::wxGetCwd();
    wxChar ch = buf.Last();
    if( ch != wxT( '/' ) ) {
      buf << wxT( "/" );
    }
    buf << wxFileFunctionsBuffer;
    buf = wxRealPath( buf );
    return MYcopystring( buf );
  }
  return MYcopystring( wxFileFunctionsBuffer );
}
wxChar *wxExpandPath( wxChar *buf, const wxChar *name ) {
  register wxChar *d, *s, *nm;
  wxChar lnm[_MAXPATHLEN];
  int q;
  wxChar trimchars[4];
  trimchars[0] = wxT( '\n' );
  trimchars[1] = wxT( ' ' );
  trimchars[2] = wxT( '\t' );
  trimchars[3] = 0;
  const wxChar     SEP = wxT( '/' );
  buf[0] = wxT( '\0' );
  if( name == NULL || *name == wxT( '\0' ) ) {
    return buf;
  }
  nm = MYcopystring( name );
  wxChar *nm_tmp = nm;
  while( wxStrchr( ( wxChar * )trimchars, *nm ) != NULL ) {
    nm++;
  }
  s = nm + ( q = wxStrlen( nm ) ) - 1;
  while( q-- && wxStrchr( ( wxChar * )trimchars, *s ) != NULL ) {
    *s = wxT( '\0' );
  }
  s = nm;
  d = lnm;
  q = nm[0] == wxT( '\\' ) && nm[1] == wxT( '~' );
  #ifdef __VISAGECPP__
  while( *d ) {
    *d++ = *s;
    if( *s == wxT( '\\' ) ) {
      *( d - 1 ) = *++s;
      if( *d ) {
        s++;
        continue;
      } else
      { break; }
    } else
  #else
  while( ( *d++ = *s ) != 0 ) {
    #  ifndef __WXMSW__
    if( *s == wxT( '\\' ) ) {
      if( ( *( d - 1 ) = *++s ) != 0 ) {
        s++;
        continue;
      } else
      { break; }
    } else
    #  endif
  #endif
      if( *s++ == wxT( '$' ) ) {
        register wxChar  *start = d;
        register int     braces = ( *s == wxT( '{' ) || *s == wxT( '(' ) );
        register wxChar  *value;
        while( ( *d++ = *s ) != 0 )
          if( braces ? ( *s == wxT( '}' ) || *s == wxT( ')' ) ) : !( wxIsalnum( *s ) || *s == wxT( '_' ) ) ) {
            break;
          } else
          { s++; }
        *--d = 0;
        value = wxGetenv( braces ? start + 1 : start );
        if( value ) {
          d--;
          if( braces && *s ) {
            s++;
          }
        }
      }
  }
  nm = lnm;
  if( nm[0] == wxT( '~' ) && !q ) {
    if( nm[1] == SEP || nm[1] == 0 ) {
      if( ( s = WXSTRINGCAST wxGetUserHome( wxEmptyString ) ) != NULL ) {
        if( *++nm ) {
          nm++;
        }
      }
    } else {
      register wxChar  *nnm;
      register wxChar  *home;
      for( s = nm; *s && *s != SEP; s++ ) {
      }
      int was_sep;
      was_sep = ( *s == SEP );
      nnm = *s ? s + 1 : s;
      *s = 0;
      if( ( home = WXSTRINGCAST wxGetUserHome( wxString( nm + 1 ) ) ) == NULL ) {
        if( was_sep ) {
          *s = SEP;
        }
        s = NULL;
      } else {
        nm = nnm;
        s = home;
      }
    }
  }
  d = buf;
  if( s && *s ) { /* MATTHEW: s could be NULL if user '~' didn't exist */
    while( wxT( '\0' ) != ( *d++ = *s++ ) )
      if( d - 1 > buf && *( d - 2 ) != SEP ) {
        *( d - 1 ) = SEP;
      }
  }
  s = nm;
  delete[] nm_tmp;
  return wxRealPath( buf );
}

wxChar * wxContractPath( const wxString& filename, const wxString& ( envname ), const wxString& user ) {
  static wxChar dest[_MAXPATHLEN];
  if( filename.empty() ) {
    return ( wxChar * ) NULL;
  }
  wxStrcpy( dest, WXSTRINGCAST filename );
  const wxChar *val;
  wxChar *tcp;
  if( !envname.empty() && ( val = wxGetenv( WXSTRINGCAST envname ) ) != NULL &&
      ( tcp = wxStrstr( dest, val ) ) != NULL ) {
    wxStrcpy( wxFileFunctionsBuffer, tcp + wxStrlen( val ) );
    *tcp++ = wxT( '$' );
    *tcp++ = wxT( '{' );
    wxStrcpy( tcp, WXSTRINGCAST envname );
    wxStrcat( tcp, wxT( "}" ) );
    wxStrcat( tcp, wxFileFunctionsBuffer );
  }
  val = wxGetUserHome( user );
  if( !val ) {
    return dest;
  }
  const size_t len = wxStrlen( val );
  if( len <= 2 ) {
    return dest;
  }
  if( wxStrncmp( dest, val, len ) == 0 ) {
    wxStrcpy( wxFileFunctionsBuffer, wxT( "~" ) );
    if( !user.empty() ) {
      wxStrcat( wxFileFunctionsBuffer, ( const wxChar* ) user );
    }
    wxStrcat( wxFileFunctionsBuffer, dest + len );
    wxStrcpy( dest, wxFileFunctionsBuffer );
  }
  return dest;
}

wxChar *wxFileNameFromPath( wxChar *path ) {
  wxString p = path;
  wxString n = wxFileNameFromPath( p );
  return path + p.length() - n.length();
}

wxString wxFileNameFromPath( const wxString& path ) {
  wxString name, ext;
  wxFileName::SplitPath( path, NULL, &name, &ext );
  wxString fullname = name;
  if( !ext.empty() ) {
    fullname << wxFILE_SEP_EXT << ext;
  }
  return fullname;
}

wxChar * wxPathOnly( wxChar *path ) {
  if( path && *path ) {
    static wxChar buf[_MAXPATHLEN];
    wxStrcpy( buf, path );
    int l = wxStrlen( path );
    int i = l - 1;
    while( i > -1 ) {
      if( path[i] == wxT( '/' ) || path[i] == wxT( '\\' ) ) {
        buf[i] = 0;
        return buf;
      }
      i --;
    }
  }
  return ( wxChar * ) NULL;
}

wxString wxPathOnly( const wxString& path ) {
  if( !path.empty() ) {
    wxChar buf[_MAXPATHLEN];
    wxStrcpy( buf, WXSTRINGCAST path );
    int l = path.length();
    int i = l - 1;
    while( i > -1 ) {
      if( path[i] == wxT( '/' ) || path[i] == wxT( '\\' ) ) {
        if( i == 0 ) {
          i ++;
        }
        buf[i] = 0;
        return wxString( buf );
      }
      i --;
    }
  }
  return wxEmptyString;
}

void wxDos2UnixFilename( wxChar *s ) {
  if( s )
    while( *s ) {
      if( *s == _T( '\\' ) ) {
        *s = _T( '/' );
      }
      s++;
    }
}

void wxUnix2DosFilename( wxChar * ( s ) ) {
}

bool wxConcatFiles( const wxString& file1, const wxString& file2, const wxString& file3 ) {
  #if wxUSE_FILE
  wxFile in1( file1 ), in2( file2 );
  wxTempFile out( file3 );
  if( !in1.IsOpened() || !in2.IsOpened() || !out.IsOpened() ) {
    return false;
  }
  ssize_t ofs;
  unsigned char buf[1024];
  for( int i = 0; i < 2; i++ ) {
    wxFile *in = i == 0 ? &in1 : &in2;
    do {
      if( ( ofs = in->Read( buf, WXSIZEOF( buf ) ) ) == wxInvalidOffset ) {
        return false;
      }
      if( ofs > 0 )
        if( !out.Write( buf, ofs ) ) {
          return false;
        }
    } while( ofs == ( ssize_t )WXSIZEOF( buf ) );
  }
  return out.Commit();
  #else
  wxUnusedVar( file1 );
  wxUnusedVar( file2 );
  wxUnusedVar( file3 );
  return false;
  #endif
}

// Copy files
bool wxCopyFile( const wxString& file1, const wxString& file2, bool overwrite ) {
  #if defined(__WIN32__) && !defined(__WXMICROWIN__)
  // CopyFile() copies file attributes and modification time too, so use it
  // instead of our code if available
  //
  // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite
  if( !::CopyFile( file1, file2, !overwrite ) ) {
    wxLogSysError( _( "Failed to copy the file '%s' to '%s'" ),
                   file1.c_str(), file2.c_str() );
    return false;
  }
  #elif defined(__OS2__)
  if( ::DosCopy( ( PSZ )file1.c_str(), ( PSZ )file2.c_str(), overwrite ? DCPY_EXISTING : 0 ) != 0 ) {
    return false;
  }
  #elif defined(__PALMOS__)
  return false;
  #elif wxUSE_FILE // !Win32
  wxStructStat fbuf;
  // get permissions of file1
  if( wxStat( file1.c_str(), &fbuf ) != 0 ) {
    // the file probably doesn't exist or we haven't the rights to read
    // from it anyhow
    wxLogSysError( _( "Impossible to get permissions for file '%s'" ),
                   file1.c_str() );
    return false;
  }
  // open file1 for reading
  wxFile fileIn( file1, wxFile::read );
  if( !fileIn.IsOpened() ) {
    return false;
  }
  // remove file2, if it exists. This is needed for creating
  // file2 with the correct permissions in the next step
  if( wxFileExists( file2 )  && ( !overwrite || !wxRemoveFile( file2 ) ) ) {
    wxLogSysError( _( "Impossible to overwrite the file '%s'" ),
                   file2.c_str() );
    return false;
  }
  // reset the umask as we want to create the file with exactly the same
  // permissions as the original one
  wxCHANGE_UMASK( 0 );
  // create file2 with the same permissions than file1 and open it for
  // writing
  wxFile fileOut;
  if( !fileOut.Create( file2, overwrite, fbuf.st_mode & 0777 ) ) {
    return false;
  }
  // copy contents of file1 to file2
  char buf[4096];
  size_t count;
  for( ;; ) {
    count = fileIn.Read( buf, WXSIZEOF( buf ) );
    if( fileIn.Error() ) {
      return false;
    }
    // end of file?
    if( !count ) {
      break;
    }
    if( fileOut.Write( buf, count ) < count ) {
      return false;
    }
  }
  if( !fileIn.Close() || !fileOut.Close() ) {
    return false;
  }
  #if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__)
  if( chmod( OS_FILENAME( file2 ), fbuf.st_mode ) != 0 ) {
    wxLogSysError( _( "Impossible to set permissions for the file '%s'" ),
                   file2.c_str() );
    return false;
  }
  #endif // OS/2 || Mac
  #else // !Win32 && ! wxUSE_FILE
  wxUnusedVar( file1 );
  wxUnusedVar( file2 );
  wxUnusedVar( overwrite );
  return false;
  #endif // __WXMSW__ && __WIN32__
  return true;
}

bool
wxRenameFile( const wxString& file1, const wxString& file2, bool overwrite ) {
  if( !overwrite && wxFileExists( file2 ) ) {
    wxLogSysError( _( "重命名文件失败 '%s' 到 '%s' 因为目标文件已经存在." ), file1.c_str(), file2.c_str() );
    return false;
  }
  if( wxRename( file1, file2 ) == 0 ) {
    return true;
  }
  if( wxCopyFile( file1, file2, overwrite ) ) {
    wxRemoveFile( file1 );
    return true;
  }
  return false;
}

bool wxRemoveFile( const wxString& file ) {
  return unlink( OS_FILENAME( file ) ) == 0;
}

bool wxMkdir( const wxString& dir, int perm ) {
  const wxChar *dirname = dir.c_str();
  if( mkdir( wxFNCONV( dirname ), perm ) != 0 ) {
    wxLogSysError( _( "目录 '%s' 无法创建" ), dirname );
    return false;
  }
  return true;
}

bool wxRmdir( const wxString& dir, int ( flags ) ) {
  return ( wxRmDir( OS_FILENAME( dir ) ) == 0 );
}

bool wxDirExists( const wxChar *pszPathName ) {
  wxString strPath( pszPathName );
  wxStructStat st;
  return wxStat( strPath.c_str(), &st ) == 0 && ( ( st.st_mode & S_IFMT ) == S_IFDIR );
}

wxChar *wxGetTempFileName( const wxString& prefix, wxChar *buf ) {
  wxString filename;
  if( !wxGetTempFileName( prefix, filename ) ) {
    return NULL;
  }
  if( buf ) {
    wxStrcpy( buf, filename );
  } else {
    buf = MYcopystring( filename );
  }
  return buf;
}

bool wxGetTempFileName( const wxString& prefix, wxString& buf ) {
  #if wxUSE_FILE
  buf = wxFileName::CreateTempFileName( prefix );
  return !buf.empty();
  #else // !wxUSE_FILE
  wxUnusedVar( prefix );
  wxUnusedVar( buf );
  return false;
  #endif // wxUSE_FILE/!wxUSE_FILE
}

static wxDir *gs_dir = NULL;
static wxString gs_dirPath;

wxString wxFindFirstFile( const wxChar *spec, int flags ) {
  wxSplitPath( spec, &gs_dirPath, NULL, NULL );
  if( gs_dirPath.empty() ) {
    gs_dirPath = wxT( "." );
  }
  if( !wxEndsWithPathSeparator( gs_dirPath ) ) {
    gs_dirPath << wxFILE_SEP_PATH;
  }
  if( gs_dir ) {
    delete gs_dir;
  }
  gs_dir = new wxDir( gs_dirPath );
  if( !gs_dir->IsOpened() ) {
    wxLogSysError( _( "无法枚举文件 '%s'" ), spec );
    return wxEmptyString;
  }
  int dirFlags;
  switch( flags ) {
    case wxDIR:
      dirFlags = wxDIR_DIRS;
      break;
    case wxFILE:
      dirFlags = wxDIR_FILES;
      break;
    default:
      dirFlags = wxDIR_DIRS | wxDIR_FILES;
      break;
  }
  wxString result;
  gs_dir->GetFirst( &result, wxFileNameFromPath( wxString( spec ) ), dirFlags );
  if( result.empty() ) {
    wxDELETE( gs_dir );
    return result;
  }
  return gs_dirPath + result;
}

wxString wxFindNextFile() {
  wxASSERT_MSG( gs_dir, wxT( "必须先调用wxFindFirstFile!" ) );
  wxString result;
  gs_dir->GetNext( &result );
  if( result.empty() ) {
    wxDELETE( gs_dir );
    return result;
  }
  return gs_dirPath + result;
}

wxChar *wxDoGetCwd( wxChar *buf, int sz ) {
  #if defined(__WXPALMOS__)
  #elif defined(__WXWINCE__)
  #else
  if( !buf ) {
    buf = new wxChar[sz + 1];
  }
  bool ok wxDUMMY_INITIALIZE( false );
  #if !wxUSE_UNICODE
#define cbuf buf
  #else // wxUSE_UNICODE
  bool needsANSI = true;
  #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU
  char cbuf[_MAXPATHLEN];
  #endif
  #ifdef HAVE_WGETCWD
  #if wxUSE_UNICODE_MSLU
  if( wxGetOsVersion() != wxOS_WINDOWS_9X )
  #else
  char *cbuf = NULL; // never really used because needsANSI will always be false
  #endif
  {
    ok = _wgetcwd( buf, sz ) != NULL;
    needsANSI = false;
  }
  #endif
  if( needsANSI )
  #endif // wxUSE_UNICODE
  {
    #if defined(_MSC_VER) || defined(__MINGW32__)
    ok = _getcwd( cbuf, sz ) != NULL;
    #elif defined(__WXMAC__) && !defined(__DARWIN__)
    #elif defined(__OS2__)
    #else // !Win32/VC++ !Mac !OS2
    ok = getcwd( cbuf, sz ) != NULL;
    #endif // platform
    #if wxUSE_UNICODE && !(defined(__WXMAC__) && !defined(__DARWIN__))
    // finally convert the result to Unicode if needed
    wxConvFile.MB2WC( buf, cbuf, sz );
    #endif // wxUSE_UNICODE
  }
  if( !ok ) {
    wxLogSysError( _( "无法获取工作目录" ) );
    buf[0] = _T( '\0' );
  } else { // ok, but we might need to massage the path into the right format
    #ifdef __DJGPP__
    for( wxChar *ch = buf; *ch; ch++ ) {
      if( *ch == wxT( '/' ) ) {
        *ch = wxT( '\\' );
      }
    }
    #endif // __DJGPP__
  }
  return buf;
  #endif
}

wxChar *wxGetWorkingDirectory( wxChar *buf, int sz ) {
  return wxDoGetCwd( buf, sz );
}

wxString wxGetCwd() {
  wxString str;
  wxDoGetCwd( wxStringBuffer( str, _MAXPATHLEN ), _MAXPATHLEN );
  return str;
}

bool wxSetWorkingDirectory( const wxString& d ) {
  return ( chdir( wxFNSTRINGCAST d.fn_str() ) == 0 );
}

wxString wxGetOSDirectory() {
  return wxEmptyString;
}

bool wxEndsWithPathSeparator( const wxChar *pszFileName ) {
  size_t len = wxStrlen( pszFileName );
  return len && wxIsPathSeparator( pszFileName[len - 1] );
}

bool wxFindFileInPath( wxString *pStr, const wxChar *pszPath, const wxChar *pszFile ) {
  wxCHECK_MSG( !wxIsEmpty( pszFile ), false, _T( "empty file name in wxFindFileInPath" ) );
  if( wxIsPathSeparator( *pszFile ) ) {
    pszFile++;
  }
  wxChar *szPath = new wxChar[wxStrlen( pszPath ) + 1];
  wxStrcpy( szPath, pszPath );
  wxString strFile;
  wxChar *pc, *save_ptr;
  for( pc = wxStrtok( szPath, wxPATH_SEP, &save_ptr ); pc != NULL;
       pc = wxStrtok( ( wxChar * ) NULL, wxPATH_SEP, &save_ptr ) ) {
    strFile = pc;
    if( !wxEndsWithPathSeparator( pc ) ) {
      strFile += wxFILE_SEP_PATH;
    }
    strFile += pszFile;
    if( wxFileExists( strFile ) ) {
      *pStr = strFile;
      break;
    }
  }
  save_ptr = pc;
  delete [] szPath;
  return pc != NULL;  // if true => we breaked from the loop
}

void wxSplitPath( const wxChar *pszFileName, wxString *pstrPath, wxString *pstrName, wxString *pstrExt ) {
  wxCHECK_RET( pszFileName, wxT( "NULL file name in wxSplitPath" ) );
  wxFileName::SplitPath( pszFileName, pstrPath, pstrName, pstrExt );
}

#if wxUSE_DATETIME

time_t wxFileModificationTime( const wxString& filename ) {
  wxDateTime mtime;
  if( !wxFileName( filename ).GetTimes( NULL, &mtime, NULL ) ) {
    return ( time_t ) - 1;
  }
  return mtime.GetTicks();
}

#endif // wxUSE_DATETIME

int wxParseCommonDialogsFilter( const wxString& filterStr,wxArrayString& descriptions,
    wxArrayString& filters ) {
  descriptions.Clear();
  filters.Clear();
  wxString str( filterStr );
  wxString description, filter;
  int pos = 0;
  while( pos != wxNOT_FOUND ) {
    pos = str.Find( wxT( '|' ) );
    if( pos == wxNOT_FOUND ) {
      if( filters.IsEmpty() ) {
        descriptions.Add( wxEmptyString );
        filters.Add( filterStr );
      } else {
        wxFAIL_MSG( _T( "missing '|' in the wildcard string!" ) );
      }
      break;
    }
    description = str.Left( pos );
    str = str.Mid( pos + 1 );
    pos = str.Find( wxT( '|' ) );
    if( pos == wxNOT_FOUND ) {
      filter = str;
    } else {
      filter = str.Left( pos );
      str = str.Mid( pos + 1 );
    }
    descriptions.Add( description );
    filters.Add( filter );
  }
  #if defined(__WXMOTIF__)
  // split it so there is one wildcard per entry
  for( size_t i = 0 ; i < descriptions.GetCount() ; i++ ) {
    pos = filters[i].Find( wxT( ';' ) );
    if( pos != wxNOT_FOUND ) {
      // first split only filters
      descriptions.Insert( descriptions[i], i + 1 );
      filters.Insert( filters[i].Mid( pos + 1 ), i + 1 );
      filters[i] = filters[i].Left( pos );
      for( size_t k = i; k < i + 2; k++ ) {
        pos = descriptions[k].Find( filters[k] );
        if( pos != wxNOT_FOUND ) {
          wxString before = descriptions[k].Left( pos );
          wxString after = descriptions[k].Mid( pos + filters[k].Len() );
          pos = before.Find( _T( '(' ), true );
          if( pos > before.Find( _T( ')' ), true ) ) {
            before = before.Left( pos + 1 );
            before << filters[k];
            pos = after.Find( _T( ')' ) );
            int pos1 = after.Find( _T( '(' ) );
            if( pos != wxNOT_FOUND && ( pos < pos1 || pos1 == wxNOT_FOUND ) ) {
              before << after.Mid( pos );
              descriptions[k] = before;
            }
          }
        }
      }
    }
  }
  #endif
  // autocompletion
  for( size_t j = 0 ; j < descriptions.GetCount() ; j++ ) {
    if( descriptions[j].empty() && !filters[j].empty() ) {
      descriptions[j].Printf( _( "Files (%s)" ), filters[j].c_str() );
    }
  }
  return filters.GetCount();
}

bool wxIsWritable( const wxString &path ) {
  #if defined( __UNIX__ ) || defined(__OS2__)
  // access() will take in count also symbolic links
  return wxAccess( path.c_str(), W_OK ) == 0;
  #elif defined( __WINDOWS__ )
  return wxCheckWin32Permission( path, GENERIC_WRITE );
  #else
  wxUnusedVar( path );
  return false;
  #endif
}

bool wxIsReadable( const wxString &path ) {
  #if defined( __UNIX__ ) || defined(__OS2__)
//  #error mmmm
  return wxAccess( path.c_str(), R_OK ) == 0;
  #elif defined( __WINDOWS__ )
  #else
  #error mmmm
  wxUnusedVar( path );
  return false;
  #endif
}

bool wxIsExecutable( const wxString &path ) {
  #if defined( __UNIX__ ) || defined(__OS2__)
  return wxAccess( path.c_str(), X_OK ) == 0;
  #elif defined( __WINDOWS__ )
  return wxCheckWin32Permission( path, GENERIC_EXECUTE );
  #else
  wxUnusedVar( path );
  return false;
  #endif
}

wxFileKind wxGetFileKind( int fd ) {
  #if defined __WXMSW__ && !defined __WXWINCE__ && defined wxGetOSFHandle
  switch( ::GetFileType( wxGetOSFHandle( fd ) ) & ~FILE_TYPE_REMOTE ) {
    case FILE_TYPE_CHAR:
      return wxFILE_KIND_TERMINAL;
    case FILE_TYPE_DISK:
      return wxFILE_KIND_DISK;
    case FILE_TYPE_PIPE:
      return wxFILE_KIND_PIPE;
  }
  return wxFILE_KIND_UNKNOWN;
  #elif defined(__UNIX__)
  if( isatty( fd ) ) {
    return wxFILE_KIND_TERMINAL;
  }
  struct stat st;
  fstat( fd, &st );
  if( S_ISFIFO( st.st_mode ) ) {
    return wxFILE_KIND_PIPE;
  }
  if( !S_ISREG( st.st_mode ) ) {
    return wxFILE_KIND_UNKNOWN;
  }
  #if defined(__VMS__)
  if( st.st_fab_rfm != FAB$C_STMLF ) {
    return wxFILE_KIND_UNKNOWN;
  }
  #endif
  return wxFILE_KIND_DISK;
  #else
#define wxFILEKIND_STUB
  ( void )fd;
  return wxFILE_KIND_DISK;
  #endif
}

wxFileKind wxGetFileKind( FILE *fp ) {
  // Note: The watcom rtl dll doesn't have fileno (the static lib does).
  //       Should be fixed in version 1.4.
  #if defined(wxFILEKIND_STUB) || wxONLY_WATCOM_EARLIER_THAN(1,4)
  ( void )fp;
  return wxFILE_KIND_DISK;
  #elif defined(__WINDOWS__) && !defined(__CYGWIN__) && !defined(__WATCOMC__) && !defined(__WINE__)
  return fp ? wxGetFileKind( _fileno( fp ) ) : wxFILE_KIND_UNKNOWN;
  #else
  return fp ? wxGetFileKind( fileno( fp ) ) : wxFILE_KIND_UNKNOWN;
  #endif
}


//------------------------------------------------------------------------
// wild character routines
//------------------------------------------------------------------------

bool wxIsWild( const wxString& pattern ) {
  wxString tmp = pattern;
  wxChar *pat = WXSTRINGCAST( tmp );
  while( *pat ) {
    switch( *pat++ ) {
      case wxT( '?' ):
      case wxT( '*' ):
      case wxT( '[' ):
      case wxT( '{' ):
        return true;
      case wxT( '\\' ):
        if( !*pat++ ) {
          return false;
        }
    }
  }
  return false;
}

/*
  Written By Douglas A. Lewis <dalewis@cs.Buffalo.EDU>

  The match procedure is public domain code (from ircII's reg.c)
  but modified to suit our tastes (RN: No "%" syntax I guess)
*/

bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special ) {
  if( text.empty() ) {
    /* Match if both are empty. */
    return pat.empty();
  }
  const wxChar *m = pat.c_str(),
                *n = text.c_str(),
                 *ma = NULL,
                  *na = NULL;
  int just = 0,
      acount = 0,
      count = 0;
  if( dot_special && ( *n == wxT( '.' ) ) ) {
    /* Never match so that hidden Unix files
      are never found. */
    return false;
  }
  for( ;; ) {
    if( *m == wxT( '*' ) ) {
      ma = ++m;
      na = n;
      just = 1;
      acount = count;
    } else if( *m == wxT( '?' ) ) {
      m++;
      if( !*n++ ) {
        return false;
      }
    } else {
      if( *m == wxT( '\\' ) ) {
        m++;
        /* Quoting "nothing" is a bad thing */
        if( !*m ) {
          return false;
        }
      }
      if( !*m ) {
        /*
          If we are out of both strings or we just
          saw a wildcard, then we can say we have a
          match
        */
        if( !*n ) {
          return true;
        }
        if( just ) {
          return true;
        }
        just = 0;
        goto not_matched;
      }
      just = 0;
      if( *m == *n ) {
        m++;
        count++;
        n++;
      } else {
      not_matched:
        if( !*n ) {
          return false;
        }
        if( ma ) {
          m = ma;
          n = ++na;
          count = acount;
        } else
        { return false; }
      }
    }
  }
}
